type E enum {
    type I interface { String: String };
    type J protected String;
};
type F {
    e: E
};
type A impl(I)
    protected Integer;
type B impl(I)
    protected String;
type R {
    u: S,
    v: I
};
type S {
    x: Integer,
    y: Integer
};

method E.String: String
    &(e) =>
        switch e:
        case I i: { "I?" i.String },
        case J j: { "J?" j.String },
        end;
method F.String: String
    &(f) => f.e.String;
method J.String: String
    &(j) => { quote j };
method A.String: String
    &(a) => a.[Integer].String;
method B.String: String
    &(b) => { quote b };
method R.String: String
    &(r) => { "(?,?)" (r.u.String, r.v.String) };
method S.String: String
    &(s) => { "(?,?)" (s.x.String, s.y.String) };
function String:
    &(I) => String
    &(i) => i.String;
function describe:
    [T] { String: &(T) => String }
    &(Maybe[T]) => String
    &(t?) =>
        switch t?:
        case Some t: { String t },
        case None: 'None',
        end;

entry
    let r := { |R| { u: { |S| { x: 1, y: 2 } }, v: { |I| { |A| 3 } } } },
    let ei := { |E| { |I| { |A| 7 } } },
    let ej := { |E| { |J| 'foo' } },
    let f := { |F| { e: ej } },
    // proj
    let t1 := r.(u).read,
    let t2 := { |R| { r.(u).write { |S| { x: 0, y: 10 } } } },
    // proj through proj
    let t3 := r.(u).(y).read,
    let t4 := { |R| { r.(u).(y).write 40 } },
    // case(enum)
    let t5 := ei.(I).read,
    let t6 := ei.(J).read,
    let t7 := ej.(J).read,
    let t8 := { ei.(I).write { |I| { |A| 8 } } },
    let t9 := { ei.(J).write { |J| "bar" } },
    // case(interface) through proj
    let t10 := r.(v).(A).read, // dynamic cast
    let t11 := r.(v).(B).read, // dynamic cast
    let t12 := { |R| { r.(v).(A).write { |A| 4 } } },
    let t13 := { |R| { r.(v).(B).write { |B| "foo" } } },
    // case(interface) through case
    let t14 := ei.(I).(A).read, // dynamic cast
    let t15 := ei.(I).(B).read, // dynamic cast
    let t16 := { ei.(I).(A).write { |A| 8 } },
    let t17 := { ei.(I).(B).write { |B| "baz" } },
    // case(enum) through proj
    let t18 := f.(e).(I).read,
    let t19 := f.(e).(J).read,
    let t20 := { |F| { f.(e).(I).write { |I| { |A| 11 } } } },
    let t21 := { |F| { f.(e).(J).write { |J| "something" } } },
    // TODO: case(enum) through case
    // TODO: case(interface) [simple dynamic cast]
    // output
    let all := [
        t1.String, t2.String, t3.String, t4.String,
        { describe t5 },
        { describe (t6 map |.String|) }, { describe (t7 map |.String|) },
        t8.String, t9.String,
        { describe (t10 map |.String|) }, { describe (t11 map |.String|) },
        t12.String, t13.String,
        { describe (t14 map |.String|) }, { describe (t15 map |.String|) },
        t16.String, t17.String,
        { describe t18 },
        { describe (t19 map |.String|) },
        t20.String, t21.String
    ],
    { concat (all map sys::println) }
    . { wait-complete }
    . { crash-on-error };


